﻿using System;
using System.Collections.Generic;

namespace CoreDB.Extensions
{
    /// <summary>
    /// 最基础的数学扩展类
    /// </summary>
    public static class MathExtension
    {
        /// <summary>
        /// 默认精度
        /// </summary>
        private const double defaultEps = 1e-6;
        /// <summary>
        /// 宽松的精度，有时候6位数国语精确
        /// </summary>
        private const double looseEps = 1e-3;

        public static bool IsEqual(this double value, double another, double eps = defaultEps)
        {
            return Math.Abs(value - another) < eps;
        }

        public static bool IsZero(this double value, double eps = defaultEps)
        {
            return value.IsEqual(0.0, eps);
        }

        public static bool IsMore(this double value, double another, double eps = defaultEps)
        {
            return (value - another) > eps;
        }
        /// <summary>
        /// 第一个数是否大于等于第二个数
        /// </summary>
        /// <param name="value"></param>
        /// <param name="another"></param>
        /// <param name="eps"></param>
        /// <returns></returns>
        public static bool IsMoreOrEqual(this double value, double another, double eps = defaultEps)
        {
            return (value - another) >= -eps;
        }
        /// <summary>
        /// a是否小于b
        /// 小于与大于等于反向
        /// </summary>
        /// <param name="value"></param>
        /// <param name="another"></param>
        /// <param name="eps"></param>
        /// <returns></returns>
        public static bool IsLess(this double value, double another, double eps = defaultEps)
        {
            return !IsMoreOrEqual(value, another, eps);
        }
        public static bool IsLessOrEqual(this double value, double another, double eps = defaultEps)
        {
            return !IsMore(value, another, eps);
        }
        /// <summary>
        /// 将双精度浮点值按指定的小数位数舍入
        /// </summary>
        /// <param name="src"></param>
        /// <param name="decimals">默认四舍五入3位</param>
        /// <returns></returns>
        public static double Round(this double src, int decimals = 3)
        {
            return Math.Round(src, decimals);
        }
        /// <summary>
        /// min ≤ value ≤ max
        /// value 是否在取值范围内
        /// (允许 Max & Min 倒置)
        /// </summary>
        /// <param name="value"></param>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <param name="eps"></param>
        /// <returns></returns>
        public static bool IsInRangeInOrEqual(this double value, double min, double max, double eps = defaultEps)
        {
            if (max.IsMoreOrEqual(min))
                return value.IsMoreOrEqual(min, eps) && value.IsLessOrEqual(max, eps);
            else
                return value.IsMoreOrEqual(max, eps) && value.IsLessOrEqual(min, eps);
        }
        /// <summary>
        /// min ＜ value ＜ max
        /// </summary>
        /// <param name="value"></param>
        /// <param name="min"></param>
        /// <param name="max"></param>
        /// <param name="eps"></param>
        /// <returns></returns>
        public static bool IsInRange(this double value, double min, double max, double eps = defaultEps)
        {
            if (max.IsMore(min))
                return value.IsMore(min) && value.IsLess(max);
            else
                return value.IsMore(max) && value.IsLess(min);
        }
        public static bool IsOutRangeOrEqual(this double value, double min, double max, double eps = defaultEps)
        {
            return !value.IsInRange(min, max, eps);
        }
        public static bool IsOutRange(this double value, double min, double max, double eps = defaultEps)
        {
            return !value.IsInRangeInOrEqual(min, max, eps);
        }
    }

    public class DoubleComparer : IEqualityComparer<double>
    {
        public double Eps { get; set; }
        public DoubleComparer(double eps = 0.001)
        {
            this.Eps = eps;
        }
        public bool Equals(double x, double y)
        {
            return x.IsEqual(y, Eps);
        }
        /// <summary>
        /// 始终指明相等，让处理相等逻辑继续交给Equals。
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public int GetHashCode(double obj)
        {
            return 0;
        }
    }

}
